package FinalProject;
import java.awt.*;
import java.net.*;
import java.io.*;
import java.util.*;
import java.awt.event.*;

import javax.swing.JFrame;

public class OmokClient extends JFrame implements Runnable, ActionListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private TextArea msgView = new TextArea("", 1, 1, 1); // text area that shows message

	private TextField sendBox = new TextField(""); // input message field

	private TextField nameBox = new TextField(); // user name input field

	private TextField roomBox = new TextField("0"); // room number input field

	// shows the number that how many people connect in room
	private Label pInfo = new Label("Waiting Room: people");

	private java.awt.List pList = new java.awt.List(); // shows user list
	
	private Button singleButton = new Button("Single Game"); // single mode
	
	private Button playButton = new Button("Start Game"); // single mode
	
	private Button endButton = new Button("End Game"); // single mode
	
	private Button networkButton = new Button("Network Game"); // network mode

	private Button startButton = new Button("Game Start"); // start button

	private Button stopButton = new Button("Give Up"); // give up button

	private Button enterButton = new Button("Enter"); // enter button

	private Button exitButton = new Button("Go to watting room"); // go to waiting room button

	// shows the information
	private Label infoView = new Label("COMP228 Final Project", 1);

	private OmokBoard board = new OmokBoard(19, 23); // Object of omok panel

	private BufferedReader reader; // input stream

	private PrintWriter writer; // output stream

	private Socket socket; // socket

	private int roomNumber = -1; // room number

	private String userName = null; // user name

	public OmokClient(String title) { // constructor

		super(title);

		setLayout(null); // don't use layout.

		// create components and add
		msgView.setEditable(false);

		infoView.setBounds(10, 10, 740, 40);

		infoView.setBackground(new Color(200, 200, 255));

		board.setLocation(10, 100);

		add(infoView);

		add(board);
		
		Panel pMode = new Panel();
		pMode.setLayout(new GridLayout(1, 2));
		pMode.add(singleButton);
		pMode.add(networkButton);
		pMode.setBounds(100, 50, 300, 20);
		
		Panel pStEd = new Panel();
		pStEd.setLayout(new GridLayout(1, 2));
		pStEd.add(playButton);
		pStEd.add(endButton);
		pStEd.setBounds(150, 75, 250, 20);
		playButton.setEnabled(false);
		endButton.setEnabled(false);
		
		Panel p = new Panel();
		p.setBackground(new Color(200, 255, 255));
		p.setLayout(new GridLayout(3, 3));


		
		p.add(new Label("Name:", 2));
		p.add(nameBox);

		p.add(new Label("Room No:", 2));
		p.add(roomBox);

		p.add(enterButton);
		p.add(exitButton);

		enterButton.setEnabled(false);
		exitButton.setEnabled(false);
		
		p.setBounds(500, 50, 250, 70);

		Panel p2 = new Panel();

		p2.setBackground(new Color(255, 255, 100));

		p2.setLayout(new BorderLayout());

		Panel p2_1 = new Panel();

		p2_1.add(startButton);
		p2_1.add(stopButton);

		p2.add(pInfo, "North");
		p2.add(pList, "Center");
		p2.add(p2_1, "South");

		startButton.setEnabled(false);
		stopButton.setEnabled(false);

		p2.setBounds(500, 120, 250, 180);

		Panel p3 = new Panel();

		p3.setLayout(new BorderLayout());

		p3.add(msgView, "Center");

		p3.add(sendBox, "South");

		p3.setBounds(500, 300, 250, 250);
		
		add(pMode);
		add(pStEd);
		add(p);
		add(p2);
		add(p3);

		// event listener
		singleButton.addActionListener(this);
		networkButton.addActionListener(this);
		sendBox.addActionListener(this);
		enterButton.addActionListener(this);
		exitButton.addActionListener(this);
		startButton.addActionListener(this);
		stopButton.addActionListener(this);
		playButton.addActionListener(this);
		endButton.addActionListener(this);

		// close window
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	public void controlAllElements(boolean con){
		nameBox.setEnabled(con);
		roomBox.setEnabled(con);
		sendBox.setEnabled(con);
		enterButton.setEnabled(con);
		exitButton.setEnabled(con);
		startButton.setEnabled(con);
		stopButton.setEnabled(con);
		//playButton.setEnabled(con);
		//endButton.setEnabled(con);
	}
	// execute action event of components
	public void actionPerformed(ActionEvent ae) {
		if (ae.getSource() == singleButton) { // action is single game
			board.setMode(OmokBoard.SINGLE);
			singleButton.setEnabled(false);
			playButton.setEnabled(false);
			endButton.setEnabled(true);
			networkButton.setEnabled(false);
			board.startGame("BLACK");
			
		}
		else if (ae.getSource() == playButton) { // action is single game
			board.startGame("BLACK"); // start game.
			singleButton.setEnabled(false);
			networkButton.setEnabled(false);
			playButton.setEnabled(false);
			endButton.setEnabled(true);
		}
		else if (ae.getSource() == endButton) { // action is single game
			singleButton.setEnabled(true);
			networkButton.setEnabled(true);
			playButton.setEnabled(true);
			endButton.setEnabled(false);
			board.stopGame();
		}
		else if (ae.getSource() == networkButton) { // action is game on connect network
			board.setMode(OmokBoard.NETWORK);
			//singleButton.setEnabled(false);
			playButton.setEnabled(false);
			endButton.setEnabled(false);
			controlAllElements(true);
			connect();
		}
		else if (ae.getSource() == sendBox) { // action is message box

			String msg = sendBox.getText();

			if (msg.length() == 0)
				return;

			if (msg.length() >= 30)
				msg = msg.substring(0, 30);

			try {

				writer.println("[MSG]" + msg);

				sendBox.setText("");

			} catch (Exception ie) {
			}

		}

		else if (ae.getSource() == enterButton) { // action is enter

			try {

				if (Integer.parseInt(roomBox.getText()) < 1) {

					infoView.setText("wrong room no. At leat 1 people.");

					return;

				}

				writer.println("[ROOM]" + Integer.parseInt(roomBox.getText()));

				msgView.setText("");

			} catch (Exception ie) {

				infoView.setText("wrong input.");

			}

		}

		else if (ae.getSource() == exitButton) { // action is waiting room

			try {

				goToWaitRoom();

				startButton.setEnabled(false);

				stopButton.setEnabled(false);

			} catch (Exception e) {
			}

		}

		else if (ae.getSource() == startButton) { // action is start game

			try {

				writer.println("[START]");

				infoView.setText("waiting for opponent's dicision.");

				startButton.setEnabled(false);

			} catch (Exception e) {
			}

		}

		else if (ae.getSource() == stopButton) { // action is give up

			try {
				//singleButton.setEnabled(true);
				
				writer.println("[DROPGAME]");

				endGame("opponent gave up.");

			} catch (Exception e) {
			}

		}

	}

	void goToWaitRoom() { // called by click waiting room button

		if (userName == null) {

			String name = nameBox.getText().trim();

			if (name.length() <= 2 || name.length() > 10) {

				infoView.setText("Wrong name format. 3~10 charactor");

				nameBox.requestFocus();

				return;

			}

			userName = name;

			writer.println("[NAME]" + userName);

			nameBox.setText(userName);

			nameBox.setEditable(false);

		}

		msgView.setText("");

		writer.println("[ROOM]0");

		infoView.setText("Enter the waiting room.");

		roomBox.setText("0");

		enterButton.setEnabled(true);

		exitButton.setEnabled(false);

	}

	public void run() {

		String msg; // message form server

		try {

			while ((msg = reader.readLine()) != null) {

				if (msg.startsWith("[STONE]")) { // opponent's stone position 

					String temp = msg.substring(7);

					int x = Integer.parseInt(temp.substring(0,
							temp.indexOf(" ")));

					int y = Integer
							.parseInt(temp.substring(temp.indexOf(" ") + 1));

					board.putOpponent(x, y); // draw opponent stone.

					board.setEnable(true); // allow user action.

				}

				else if (msg.startsWith("[ROOM]")) { // enter the room

					if (!msg.equals("[ROOM]0")) { // is not a waiting room

						enterButton.setEnabled(false);

						exitButton.setEnabled(true);

						infoView.setText("Enter No. "+msg.substring(6) + " room.");

					}

					else
						infoView.setText("Enter the waiting room.");

					    roomNumber = Integer.parseInt(msg.substring(6)); // specify room number

					if (board.isRunning()) { // if game is running?

						board.stopGame(); // stop the game.

					}

				}

				else if (msg.startsWith("[FULL]")) { // if the room is full

					infoView.setText("Room is already full.");

				}

				else if (msg.startsWith("[PLAYERS]")) { // list of people in room

					nameList(msg.substring(9));

				}

				else if (msg.startsWith("[ENTER]")) { // enter the guest

					pList.add(msg.substring(7));

					playersInfo();

					msgView.append("Entered [" + msg.substring(7) + "]\n");

				}

				else if (msg.startsWith("[EXIT]")) { // exit guest

					pList.remove(msg.substring(6)); // remove from list

					playersInfo(); // recalculate number of people and show it.

					msgView.append("User [" + msg.substring(6) +

					"] Entered different room.\n");

					if (roomNumber != 0)

						endGame("Went out opponent.");

				}

				else if (msg.startsWith("[DISCONNECT]")) { // guest disconnect

					pList.remove(msg.substring(12));

					playersInfo();

					msgView.append("User [" + msg.substring(12) + "] closes the connection.\n");

					if (roomNumber != 0)

						endGame("Opponent went out.");

				}

				else if (msg.startsWith("[COLOR]")) { // get a stone color .

					String color = msg.substring(7);

					board.startGame(color); // start game.

					if (color.equals("BLACK"))

						infoView.setText("Your stone color is black.");

					else

						infoView.setText("Your stone color is white.");

					stopButton.setEnabled(true); // Enable Give up button

				}

				else if (msg.startsWith("[DROPGAME]")) // if opponent gives up
				{
					singleButton.setEnabled(true);
					endGame("Opponent gave up.");
				}
				else if (msg.startsWith("[WIN]")) // if win

					endGame("You won.");

				else if (msg.startsWith("[LOSE]")) // if lose

					endGame("You lost.");

				// message is not command, show on message area

				else
					msgView.append(msg + "\n");

			}

		} catch (IOException ie) {

			msgView.append(ie + "\n");

		}

		msgView.append("Disconnected.");

	}

	private void endGame(String msg) { // method for finish game

		infoView.setText(msg);

		startButton.setEnabled(false);

		stopButton.setEnabled(false);

		try {
			Thread.sleep(2000);
		} catch (Exception e) {
		} // wait 2sec

		if (board.isRunning())
			board.stopGame();

		if (pList.getItemCount() == 2)
			startButton.setEnabled(true);

	}

	private void playersInfo() { // shows the number who is in a room

		int count = pList.getItemCount();

		if (roomNumber == 0)

			pInfo.setText("Waiting Room: " + count + "people");

		else
			pInfo.setText("Room No. "+roomNumber + " : " + count + "people");

		// check enable status of start button

		if (count == 2 && roomNumber != 0)

			startButton.setEnabled(true);

		else
			startButton.setEnabled(false);

	}

	// pick up user list and add list to pList.

	private void nameList(String msg) {

		pList.removeAll();

		StringTokenizer st = new StringTokenizer(msg, "\t");

		while (st.hasMoreElements())

			pList.add(st.nextToken());

		playersInfo();

	}

	private void connect() { // connection

		try {

			msgView.append("Request connection to server.\n");

			socket = new Socket("127.0.0.1", 7777);

			msgView.append("---connect success--.\n");

			msgView.append("Input your name and enter the waiting room.\n");

			reader = new BufferedReader(

			new InputStreamReader(socket.getInputStream()));

			writer = new PrintWriter(socket.getOutputStream(), true);

			new Thread(this).start();

			board.setWriter(writer);

		} catch (Exception e) {

			msgView.append(e + "\n\nfailed connection..\n");

		}

	}

	public static void main(String[] args) {

		OmokClient client = new OmokClient("Omok Game");

		client.setSize(770, 600);

		client.setVisible(true);

		client.controlAllElements(false);
		//client.connect();

	}

}